#include "httpclient.h"

#include <QEventLoop>
#include <QNetworkReply>
#include <QTimer>
#include <QUrlQuery>

Response HttpClient::head(Request req)
{
    QNetworkAccessManager httpmanager;

    QNetworkRequest request = do1(req);

    QNetworkReply *reply = httpmanager.head(request);

    QEventLoop eventloop;
    connect(reply, &QNetworkReply::finished, &eventloop, &QEventLoop::quit);
    eventloop.exec();

    Response resp(reply);
    if (resp.status() == 301 || resp.status() == 302) {
        // resp.setLocation(Response(reply).location());
        if (m_auto_location) {
            req.setUrl(resp.location());
            return head(req);
        }
    }
    return resp;
}

Response HttpClient::get(Request req)
{
    QNetworkAccessManager httpmanager;

    QNetworkRequest request = do1(req);
    request.setUrl(req.queryUrl());

    {
        qDebug() << ">" << "GET" << request.url();
        auto allHeaders = request.rawHeaderList();
        for (const QByteArray &headerName : allHeaders) {
            QByteArray headerValue = request.rawHeader(headerName);
            qDebug() << ">" << headerName << ": " << headerValue;
        }
    }

    QNetworkReply *reply = httpmanager.get(request);

    QEventLoop eventloop;
    connect(reply, &QNetworkReply::finished, &eventloop, &QEventLoop::quit);
    eventloop.exec();

    QByteArray replyData = reply->readAll();
    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    QVariantMap headers;
    if (reply) {
        qDebug() << "<" << "HTTP: " << statusCode;
        auto allHeaders = reply->rawHeaderList();
        for (const QByteArray &headerName : allHeaders) {
            QByteArray headerValue = reply->rawHeader(headerName);
            headers[headerName] = headerValue;
        }
    }

    Response resp(statusCode, replyData, headers);
    if (resp.status() == 301 || resp.status() == 302 || resp.status() == 307) {
        resp.setLocation(Response(reply).location());
        if (m_auto_location) {
            req.setUrl(resp.location());
            return get(req);
        }
    }
    return resp;
}

Response HttpClient::post(Request req)
{
    QNetworkAccessManager httpmanager;

    QNetworkRequest request = do1(req);

// TODO:
//#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
//    request.setTransferTimeout(req.timeout());

//    QEventLoop eventloop;
//    QNetworkReply *reply = httpmanager.post(request, req.data());
//    connect(reply, &QNetworkReply::finished, &eventloop, &QEventLoop::quit);
//    eventloop.exec();
//#else
//    QTimer timerout;
//    timerout.setInterval(req.timeout());
//    timerout.setSingleShot(true);

//    QEventLoop eventloop;
//    QTimer::singleShot(req.timeout(), &eventloop, &QEventLoop::quit);

//    QNetworkReply *reply = httpmanager.post(request, req.data());
//    connect(reply, &QNetworkReply::finished, &timerout, &QTimer::stop);
//    connect(reply, &QNetworkReply::finished, &eventloop, &QEventLoop::quit);
//    timerout.connect(&timerout, &QTimer::timeout, &eventloop, &QEventLoop::quit);
//    timerout.start();

//    eventloop.exec();
//    timerout.stop();
//#endif

    QNetworkReply *reply = httpmanager.post(request, req.data());

    QEventLoop eventloop;
    connect(reply, &QNetworkReply::finished, &eventloop, &QEventLoop::quit);
    eventloop.exec();

    QByteArray replyData = reply->readAll();
    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    Response resp(statusCode, replyData);
    
    if (resp.status() == 301 || resp.status() == 302) {
        resp.setLocation(Response(reply).location());
        if (m_auto_location) {
            req.setUrl(resp.location());
            return post(req);
        }
    }

    if (statusCode == 200)
    {
        QNetworkCookie cookie;
        QVariant variantCookies = reply->header(QNetworkRequest::SetCookieHeader);

        if (variantCookies.isValid())
        {
            QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie>>(variantCookies);
            resp.setCookies(cookies);
        }
    }

    return resp;
}

Response HttpClient::head(QString url)
{
    return head(Request(url));
}

Response HttpClient::get(QString url)
{
    return get(Request(url));
}

void HttpClient::setCookies(QList<QNetworkCookie> cookies)
{
    m_cookies = cookies;
}

void HttpClient::setCookies(QList<QNetworkCookie> &cookies)
{
    m_cookies = cookies;
}

void HttpClient::setAutoAccept(bool newAutoAccept)
{
    m_auto_accept = newAutoAccept;
}

void HttpClient::setAutoHost(bool newAutoHost)
{
    m_auto_host = newAutoHost;
}

void HttpClient::setAutoUserAgent(bool newAutoUserAgent, QString newUserAgent)
{
    m_auto_user_agent = newAutoUserAgent;
    m_user_agent = newUserAgent;
}

void HttpClient::setAutoLocation(bool new_auto_location)
{
    m_auto_location = new_auto_location;
}

QNetworkRequest HttpClient::do1(Request &req)
{
    // 构造一个 request
    QNetworkRequest request;
    request.setUrl(req.url());

    // 配置 SSL 连接
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
    QSslConfiguration sslconfig;
    sslconfig.setProtocol(QSsl::TlsV1SslV3);
#else
    QSslConfiguration sslconfig;
    sslconfig.setProtocol(QSsl::SecureProtocols);
#endif
    request.setSslConfiguration(sslconfig);

    // 配置 request 的请求头信息
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    if (m_cookies.isEmpty() == false) {
        request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(m_cookies));
    }
    applyRequestHeaders(req, request);

    return request;
}

void HttpClient::applyRequestHeaders(Request &req, QNetworkRequest &request)
{
    req.requestParserHeaders(request);
    if (m_auto_accept) {
        if (request.hasRawHeader("Accept") == false) {
            request.setRawHeader("Accept", "*/*");
        }
    }
    if (m_auto_host) {
        if (request.hasRawHeader("Host") == false) {
            request.setRawHeader("Host", req.url().host().toUtf8());
        }
    }
    if (m_auto_user_agent) {
        if (request.hasRawHeader("User-Agent") == false) {
            request.setRawHeader("User-Agent", m_user_agent.toUtf8());
        }
    }
    if (m_auto_location) {
        // Do Nothing
    }
}
